package com.example.test;

import com.example.test.annotation.AclItem;
import com.example.test.domain.AccessControlItem;
import com.example.test.domain.Role;
import com.example.test.security.CustomSecurityMetadataSource;
import com.example.test.service.IRoleService;
import lombok.Getter;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 权限扫描器
 */
@Component
public class AclScanner implements CommandLineRunner {
    private final RequestMappingHandlerMapping requestMappingHandlerMapping;
    private final IRoleService roleService;
    /**
     * 储存所有权限列表
     */
    @Getter
    private Set<String> authoritySet = new HashSet<>();

    public AclScanner(RequestMappingHandlerMapping requestMappingHandlerMapping, IRoleService roleService) {
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
        this.roleService = roleService;
    }

    @Override
    public void run(String... args) {
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
        Map<AccessControlItem, Collection<ConfigAttribute>> acl = new HashMap<>();
        List<Role> roleList = roleService.findAll();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethodMap.entrySet()) {
            AclItem aclItem = entry.getValue().getMethodAnnotation(AclItem.class);
            if(aclItem == null) continue;
            AccessControlItem accessControlItem = new AccessControlItem(aclItem, entry.getKey(), entry.getValue());
            authoritySet.add(accessControlItem.getCode());
            acl.put(accessControlItem, roleList.stream().filter(role ->
                role.getAuthorities().contains(accessControlItem.getCode())
            ).collect(Collectors.toList()));
        }
//        验证角色的权限是否有效
        for (Role role : roleList) {
            for (String authority : role.getAuthorities()) {
                Assert.isTrue(authoritySet.contains(authority), String.format("角色[%s]的权限[%s]不存在", role.getName(), authority));
            }
        }
        CustomSecurityMetadataSource.setAcl(acl);
    }
}
